package cn.lhf.cd.controller;

import cn.lhf.cd.FXApplication;
import cn.lhf.cd.Main;
import cn.lhf.cd.annotation.FXController;
import cn.lhf.cd.entity.Goods;
import cn.lhf.cd.mapper.GoodsMapper;
import cn.lhf.cd.utils.StringUtils;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
import javafx.util.Callback;
import org.apache.ibatis.session.SqlSession;

import java.math.BigDecimal;
import java.net.URL;
import java.util.*;

@FXController(path = "/ui/admin_home.fxml")
public class AdminHomeController implements Initializable {

    public TreeView<String> treeView;   //左边的树
    public TextArea infoView;           //右边的框
    private TreeItem<String> rootNode;  //树根
    private Hashtable<TreeItem<String>, Goods> goodsHashtable = new Hashtable<>();    //商品表，与相应的树叶关联

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        rootNode = createTypeNode("商品分类"); //创建树根
        rootNode.setExpanded(true);
        SqlSession sqlSession = Main.openSqlSession();
        for (Goods goods : sqlSession.getMapper(GoodsMapper.class).getAll()) {
            mountGoodsNode(goods);  //把商品挂上去
        }
        sqlSession.close();
        treeView.setRoot(rootNode); //设置树根
        treeView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            //监听选择节点事件
            if (isGoodsNode(newValue)) { //选择的是商品节点
                Goods goods = goodsHashtable.get(newValue);    //取出商品信息
                showGoods(goods);                             //展示商品信息
            } else {
                infoView.setText(null);                     //清空右边白板
            }
        });
    }

    /**
     * 点击了添加按钮
     *
     * @param event 事件
     * @throws Exception 神奇的异常
     */
    public void onAppend(ActionEvent event) throws Exception {
        openGoodsInfoEditorDialog(null, controller -> {    //打开商品信息填写窗口
            //获取填写的商品信息
            String name = controller.getName();
            BigDecimal price = new BigDecimal(controller.getPrice());
            String type = controller.getType();
            String info = controller.getDetail();

            //保存到数据库
            SqlSession sqlSession = Main.openSqlSession();
            Goods goods = new Goods(name, price, type, info);
            sqlSession.getMapper(GoodsMapper.class).add(goods);
            sqlSession.commit();
            sqlSession.close();

            //挂载到树上，然后刷新树视图
            mountGoodsNode(goods);
            refreshTree();
            return null;
        });
    }

    /**
     * 点击了编辑按钮
     *
     * @param event 事件
     * @throws Exception 神奇的异常
     */
    public void onEdit(ActionEvent event) throws Exception {
        TreeItem<String> selectedItem = treeView.getSelectionModel().getSelectedItem(); //获取被选择的节点
        if (isGoodsNode(selectedItem)) {     //选择的是商品
            Goods goods = goodsHashtable.get(selectedItem);    //获取商品信息
            openGoodsInfoEditorDialog(goods, controller -> {    //打开商品信息填写窗口
                //获取填写的数据
                String name = controller.getName();
                BigDecimal price = new BigDecimal(controller.getPrice());
                String type = controller.getType();
                String info = controller.getDetail();

                TreeItem<String> typeNode = selectedItem.getParent();   //获取父节点
                if (!goods.getType().equals(type)) {                     //商品分类发生了变化
                    typeNode.getChildren().remove(selectedItem);        //从旧的分类节点上删除
                    typeNode = parseTypeNode(type);                     //重新解析分类节点
                    typeNode.getChildren().add(selectedItem);           //把商品节点挂到分类节点上
                } else {                                                //商品分类没有发生变亿
                    selectedItem.setValue(name);                        //更改节点的内容
                }
                //更新商品信息
                goods.setName(name);
                goods.setPrice(price);
                goods.setType(type);
                goods.setDetail(info);

                //将更改保存至数据库
                SqlSession sqlSession = Main.openSqlSession();
                sqlSession.getMapper(GoodsMapper.class).save(goods);
                sqlSession.commit();
                sqlSession.close();

                //展示商品信息，且刷新树视图
                showGoods(goods);
                refreshTree();
                treeView.getSelectionModel().select(selectedItem);  //选择商品
                return null;
            });
        }
    }

    /**
     * 点击了删除按钮
     *
     * @param event 神奇的事件
     */
    public void onDelete(ActionEvent event) {
        TreeItem<String> selectedItem = treeView.getSelectionModel().getSelectedItem(); //获取已选择的节点
        if (isGoodsNode(selectedItem)) {    //它是商品节点
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION);  //打开一个询问窗口

            alert.setTitle("确认？");  //标题
            alert.setHeaderText(null);  //不要头
            alert.setContentText("是否删除" + selectedItem.getValue() + "？");   //内容
            FXApplication.setAlertFont(alert, new Font(18));    //设置字体
            Optional<ButtonType> result = alert.showAndWait();      //显示窗口且等待关闭
            if (result.isPresent() && result.get() == ButtonType.OK) {  //是确定按钮
                Goods goods = goodsHashtable.remove(selectedItem);  //从映射表中删除

                //从数据库删除
                SqlSession sqlSession = Main.openSqlSession();
                sqlSession.getMapper(GoodsMapper.class).remove(goods.getId());
                sqlSession.commit();
                sqlSession.close();

                //从它的父节点中删除，然后刷新树
                selectedItem.getParent().getChildren().remove(selectedItem);
                refreshTree();
            }
        }
    }

    /**
     * 点击了退出按钮
     *
     * @param event 神奇的事件
     */
    public void onExit(ActionEvent event) {
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
        alert.setTitle("确认？");
        alert.setHeaderText(null);
        alert.setContentText("是否退出本程序？");
        FXApplication.setAlertFont(alert, new Font(18));
        Optional<ButtonType> result = alert.showAndWait();
        if (result.isPresent() && result.get() == ButtonType.OK) {
            Platform.exit();
        }
    }

    /**
     * 清理空的分类节点
     */
    private void clearEmptyTypeNode(TreeItem<String> node) {
        Iterator<TreeItem<String>> iterator = node.getChildren().iterator();    //取出迭代器
        while (iterator.hasNext()) { //如果有下一个
            TreeItem<String> children = iterator.next();    //下一个
            if (isGoodsNode(children)) {    //是商品节点，跳过
                continue;
            }
            clearEmptyTypeNode(children);   //递归清理下一级分类
            if (children.isLeaf())          //是空节点，删除当前节点
                iterator.remove();
        }
    }

    /**
     * 刷新树
     */
    private void refreshTree() {
        clearEmptyTypeNode(rootNode);
        treeView.refresh();             //刷新树视图
    }

    /**
     * 在右边白板中展示商品信息
     *
     * @param goods 商品信息
     */
    private void showGoods(Goods goods) {
        infoView.setText(String.format("%s\n价格: ￥%.02f\n商品介绍：\n%s", goods.getName(), goods.getPrice(),
                goods.getDetail()));
    }

    /**
     * 打开商品信息编辑弹窗
     *
     * @param goods    原来的商品信息
     * @param callback 保存回调
     * @throws Exception 神奇的异常
     */
    private void openGoodsInfoEditorDialog(Goods goods, Callback<GoodsInfoDialogController, Void> callback) throws Exception {
        FXMLLoader loader = FXApplication.loadFXML(GoodsInfoDialogController.class); //加载类绑定的fxml
        Pane pane = loader.load();
        GoodsInfoDialogController controller = loader.getController();
        Alert alert = new Alert(Alert.AlertType.NONE);                              //无头无体无尾的空白弹窗
        if (goods != null) {
            //如果有原来的信息，就设置上
            controller.setName(goods.getName());
            controller.setPrice(goods.getPrice());
            controller.setType(goods.getType());
            controller.setDetail(goods.getDetail());
            alert.setTitle("编辑商品");
        } else {
            alert.setTitle("增加商品");
        }
        //两个按钮
        ButtonType buttonTypeSave = new ButtonType("保存", ButtonBar.ButtonData.OK_DONE);
        ButtonType buttonTypeCancel = new ButtonType("取消", ButtonBar.ButtonData.CANCEL_CLOSE);

        alert.getButtonTypes().addAll(buttonTypeSave, buttonTypeCancel);            //添加按钮
        FXApplication.setAlertFont(alert, new Font(18));
        alert.getDialogPane().setContent(pane);                                     //填充弹窗
        Optional<ButtonType> result = alert.showAndWait();                          //显示窗口，等待结束，并取得点击的按钮
        if (result.isPresent() && result.get() == buttonTypeSave) {                 //是保存按钮
            callback.call(controller);                                              //执行回调
        }
    }

    /**
     * 创建分类节点
     *
     * @param value 分类名字
     * @return 节点
     */
    private TreeItem<String> createTypeNode(String value) {
        TreeItem<String> node = new TreeItem<>(value);
//        node.setExpanded(true);
        node.setGraphic(new ImageView("/img/empty-folder.png"));    //图标
        return node;
    }

    /**
     * 把商品挂到树上去
     *
     * @param goods 被挂的商品
     */
    private void mountGoodsNode(Goods goods) {
        parseTypeNode(goods.getType()).getChildren().add(createGoodsNode(goods));
    }

    /**
     * 创建商品节点，且把商品保存到表中
     *
     * @param goods 可爱的商品
     * @return 商品节点
     */
    private TreeItem<String> createGoodsNode(Goods goods) {
        TreeItem<String> node = new TreeItem<>(goods.getName());
        ImageView graphic = new ImageView("/img/file.png");
        node.setGraphic(graphic);
        goodsHashtable.put(node, goods);
        return node;
    }

    /**
     * 判断节点是否为商品
     *
     * @param node 节点
     * @return 是商品则返回true
     */
    private boolean isGoodsNode(TreeItem<String> node) {
        return node != null && goodsHashtable.containsKey(node);
    }

    /**
     * 解析分类节点
     *
     * @param str 分类字符串
     * @return 树节点
     */
    private TreeItem<String> parseTypeNode(String str) {
        if (StringUtils.isEmpty(str))
            return rootNode;
        String[] arr = str.split("\\s+");   //每个子分类以空白字符分隔
        TreeItem<String> parentNode = rootNode;   //从树根开始
        for (String s : arr) {
            boolean findFlag = false;             //查找标记

            for (TreeItem<String> node : parentNode.getChildren()) {
                if (node.getValue().equals(s) && !isGoodsNode(node)) {    //当前子分类节点已存在
                    parentNode = node;              //进入子分类节点
                    findFlag = true;
                    break;
                }
            }

            if (!findFlag) {    //找不到子分类节点
                TreeItem<String> temp = createTypeNode(s);  //创建子分类节点
                parentNode.getChildren().add(temp);         //挂载子分类节点
                parentNode = temp;                          //进入子分类节点
            }
        }
        return parentNode;                                  //返回已解析好的分类节点
    }
}
